import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { DiscordSnowflake } from "@sapphire/snowflake";
import { plainToInstance } from "class-transformer";
import { In, Like, Repository } from "typeorm";
import { ResultMsg } from "@/common/enum/result-msg.enum";
import Result from "@/common/utils/result.util";
import { SysCascaderItem } from "@/database/entity/SysCascaderItem";
import { CreateCascaderItemDto } from "./dto/create-csdr-item.dto";
import { UpdateCascaderItemDto } from "./dto/update-csdr-item.dto";
import { CascaderItemDetailVo } from "./vo/csdr-item-detail.vo";
import { CascaderItemOptionVo } from "./vo/csdr-item-option.vo";
import { CascaderItemTreeVo } from "./vo/csdr-item-tree";
import { CascaderItemTreeListVo } from "./vo/csdr-item-tree-list.vo";

@Injectable()
export class CascaderItemService {
    constructor(
        @InjectRepository(SysCascaderItem) private readonly cascaderItemRepository: Repository<SysCascaderItem>,
    ) {}

    /** 新增级联字典项 */
    async create(data: CreateCascaderItemDto) {
        const id = DiscordSnowflake.generate().toString();
        const entity = this.cascaderItemRepository.create({ ...data, id });
        await this.cascaderItemRepository.save(entity);
        return Result.success(id, ResultMsg.CREATE_SUCCESS);
    }

    /** 删除级联字典项 */
    async remove(code: string, typeId: string) {
        await this.cascaderItemRepository.update({ code: Like(`${code}%`), typeId }, { deletedAt: new Date() });
        return Result.success(null, ResultMsg.DELETE_SUCCESS);
    }

    /** 更新级联字典项 */
    async update(data: UpdateCascaderItemDto) {
        await this.cascaderItemRepository.update(data.id, { ...data });
        return Result.success(null, ResultMsg.UPDATE_SUCCESS);
    }

    /** 查看详情 */
    async findById(id: string): Promise<Result<CascaderItemDetailVo>> {
        const record = await this.cascaderItemRepository.findOne({
            select: ["id", "name", "code", "status", "rank", "remark"],
            where: { id },
        });
        const detailVo = plainToInstance(CascaderItemDetailVo, record, { excludeExtraneousValues: true });
        return Result.success(detailVo);
    }

    /** 根据code查询路径 */
    async findPathByCode(code: string): Promise<Result<CascaderItemOptionVo[]>> {
        const codePath: string[] = [];
        code.split(".").reduce((prev, cur) => {
            if (prev) {
                codePath.push(`${prev}`);
                return `${prev}.${cur}`;
            }
            return cur;
        });
        codePath.push(code);

        const list = await this.cascaderItemRepository.find({
            select: ["id", "name", "code"],
            where: { code: In(codePath) },
            order: { code: "ASC" },
        });
        const voList = plainToInstance(CascaderItemOptionVo, list, { excludeExtraneousValues: true });
        return Result.success(voList);
    }

    /** 获取级联选项 */
    async listOptions(typeCode: string) {
        const list = await this.cascaderItemRepository.find({
            select: ["id", "parentId", "name", "code"],
            where: {
                typeCode,
                status: true,
            },
            order: {
                rank: "ASC",
                createdAt: "DESC",
            },
        });
        const tree = buildCascaderItemTree(list);
        const voTree = plainToInstance(CascaderItemTreeVo, tree, { excludeExtraneousValues: true });
        return Result.success(voTree);
    }

    /** 查询树形列表 */
    async listTree(typeCode: string) {
        const categories = await this.cascaderItemRepository.find({
            select: ["id", "typeId", "parentId", "code", "name", "status", "rank"],
            where: { typeCode },
            order: {
                rank: "ASC",
                createdAt: "DESC",
            },
        });
        const tree = buildCascaderItemTree(categories);
        return Result.success(tree);
    }
}

/** 构建分类字典树 */
function buildCascaderItemTree(items: SysCascaderItem[]): CascaderItemTreeListVo[] {
    const map = new Map<string, CascaderItemTreeListVo>();
    const roots: CascaderItemTreeListVo[] = [];

    items.forEach((item) => {
        map.set(item.id, { ...item, isLeaf: true, children: [] });
    });

    map.forEach((item) => {
        if (!item.parentId) {
            roots.push(item);
        } else {
            const parent = map.get(item.parentId);
            if (parent) {
                parent.children?.push(item);
                parent.isLeaf = false;
            }
        }
    });

    return roots;
}
